Ext.ns("org.cancerregulome.redi");

org.cancerregulome.redi.MainPanel = Ext.extend(Ext.Panel, {
    layout: "border",
    datasets: {},
    projectsMenu: new Ext.menu.Menu({}),
    tbar: new Ext.Toolbar({ hideBorders: true, height: 30, items: [] }),

    constructor: function(config) {
        Ext.apply(this, config);

        this.addEvents("loaded", "projects-ready");

        org.cancerregulome.redi.MainPanel.superclass.constructor.call(this);
        this.on("render", this.loadProjectsMenu, this);
        this.on("projects-ready", this.loadDatasetsMenu, this);

        this.datasetsMenu = new org.cancerregulome.redi.PathedMenu({});
        this.datasetTabPanel = new Ext.TabPanel({ enableTabScroll: true, region: "center", margins: "5 5 5 5" });
        this.add(this.datasetTabPanel);

        this.getTopToolbar().add({ text: "Projects", menu: this.projectsMenu });
        this.getTopToolbar().add({ text: "Datasets", menu: this.datasetsMenu });
    },

    loadProjectsMenu: function() {
        Ext.Ajax.request({
            url: this.url,
            method: "GET",
            scope: this,
            success: function(o) {
                var json = Ext.util.JSON.decode(o.responseText);
                if (json && json.items) {
                    var menuItems = [];
                    Ext.each(json.items, function(item) {
                        item.text = item.label;
                        item.menu = [];
                        menuItems.push(item);
                    }, this);

                    menuItems.sort(org.cancerregulome.redi.LabelSorter);
                    Ext.each(menuItems, function(item) {
                        this.projectsMenu.addMenuItem(item);
                    }, this);

                    this.getTopToolbar().doLayout();
                    this.fireEvent("projects-ready");
                }
            }
        });
    },

    loadDatasetsMenu: function() {
        Ext.each(this.projectsMenu.items.items, function(project) {
            Ext.Ajax.request({
                url: project.uri,
                method: "GET",
                scope: this,
                success: function(o) {
                    var json = Ext.util.JSON.decode(o.responseText);
                    if (json && json.items && json.items.length) {
                        var menuItems = [];
                        Ext.each(json.items, function(item) {
                            menuItems.push(this.newMenuItem(item));
                            this.datasetsMenu.menuItems.push(this.newMenuItem(item));
                        }, this);

                        menuItems.sort(org.cancerregulome.redi.LabelSorter);
                        Ext.each(menuItems, function(item) {
                            project.menu.add(item);
                        });

                        this.datasetsMenu.buildMenus(org.cancerregulome.redi.LabelSorter);
                    } else {
                        project.menu.addMenuItem( { text: "No Datasets Found" });
                    }
                },
                failure: function() {
                    project.menu.addMenuItem( { text: "Error Loading Datasets" });
                }
            });
        }, this);
    },

    newMenuItem: function(item) {
        var config = {
            id: Ext.id(),
            dsid: item.id,
            text: item.label,
            scope: this,
            handler: this.displayDataset
        };
        return new Ext.menu.Item(Ext.applyIf(config, item));
    },

    displayDataset: function(item) {
        var tab = new org.cancerregulome.redi.DatasetPanel(item);
        this.datasetTabPanel.add(tab);
        this.datasetTabPanel.setActiveTab(tab);
    }
});

org.cancerregulome.redi.DatasetPanel = Ext.extend(Ext.Panel, {
    closable: true,
    layout: "border",

    constructor: function(item) {
        this.dsid = item.dsid;
        this.id = item.uri;
        this.uri = item.uri;
        this.title = item.label;

        org.cancerregulome.redi.DatasetPanel.superclass.constructor.call(this);

        var store_features = new Ext.data.JsonStore({ idProperty: 'id', fields: ['id', 'label', 'table', 'type'], data: [] });
        var store_annotations = new Ext.data.JsonStore({ idProperty: 'id', fields: ['id', 'label', 'table', 'type'], data: [] });
        var store_statistics = new Ext.data.JsonStore({ idProperty: 'id', fields: ['id', 'label', 'table', 'type'], data: [] });
        var store_alias = new Ext.data.JsonStore({ idProperty: 'id', fields: ['id', 'label', 'table', 'type'], data: [] });
        var store_references = new Ext.data.JsonStore({ idProperty: 'id', fields: ['id', 'label', 'table', 'type'], data: [] });
        var store_associations = new Ext.data.JsonStore({ idProperty: 'id', fields: ['id', 'label', 'table', 'type'], data: [] });

        this.dataview_features = new Ext.DataView({
            store: store_features,
            tpl: new Ext.XTemplate(
                '<div><h3>Features</h3><ul id="features">',
                '<tpl for="."><li id="{id}">{label}</li></tpl>',
                '</ul></div><hr/>'
            ),
            region: "west", width: 240, margins: "5 5 5 5",
            itemSelector: "li",
            emptyText: "No Features Found",
            listeners: {
                scope: this,
                click: this.displayDetails
            }
        });
        this.dataview_annotations = new Ext.DataView({
            store: store_annotations,
            tpl: new Ext.XTemplate(
                '<div><h3>Annotations</h3><ul id="annotations">',
                '<tpl for="."><li id="{id}">{label}</li></tpl>',
                '</ul></div><hr/>'
            ),
            region: "west", width: 240, margins: "5 5 5 5",
            itemSelector: "li",
            emptyText: "No Annotations Found",
            listeners: {
                scope: this,
                click: this.displayDetails
            }
        });
        this.dataview_statistics = new Ext.DataView({
            store: store_statistics,
            tpl: new Ext.XTemplate(
                '<div><h3>Statistics</h3><ul id="statistics">',
                '<tpl for="."><li id="{id}">{label}</li></tpl>',
                '</ul></div><hr/>'
            ),
            region: "west", width: 240, margins: "5 5 5 5",
            itemSelector: "li",
            emptyText: "No Statistics Found",
            listeners: {
                scope: this,
                click: this.displayDetails
            }
        });
        this.dataview_associations = new Ext.DataView({
            store: store_associations,
            tpl: new Ext.XTemplate(
                '<div><h3>Associations</h3><ul id="associations">',
                '<tpl for="."><li id="{id}">{label}</li></tpl>',
                '</ul></div><hr/>'
            ),
            region: "west", width: 240, margins: "5 5 5 5",
            itemSelector: "li",
            emptyText: "No Associations Found",
            listeners: {
                scope: this,
                click: this.displayDetails
            }
        });

        this.dataview_alias = new Ext.DataView({
            store: store_alias,
            tpl: new Ext.XTemplate(
                '<div><h3>Alias</h3><ul id="alias">',
                '<tpl for="."><li id="{id}">{label}</li></tpl>',
                '</ul></div><hr/>'
            ),
            region: "west", width: 240, margins: "5 5 5 5",
            itemSelector: "li",
            emptyText: "No Alias Found",
            listeners: {
                scope: this,
                click: this.displayDetails
            }
        });

        this.dataview_references = new Ext.DataView({
            store: store_references,
            tpl: new Ext.XTemplate(
                '<div><h3>References</h3><ul id="references">',
                '<tpl for="."><li id="{id}">{label}</li></tpl>',
                '</ul></div><hr/>'
            ),
            region: "west", width: 240, margins: "5 5 5 5",
            itemSelector: "li",
            emptyText: "No References Found",
            listeners: {
                scope: this,
                click: this.displayDetails
            }
        });

        this.add(new Ext.Panel({
            region: "west",
            width: 240,
            frame: true,
            items: [ this.dataview_features, this.dataview_annotations, this.dataview_statistics, this.dataview_alias, this.dataview_references, this.dataview_associations ]
        }));

        this.datasetDetailPanel = this.add(new org.cancerregulome.redi.DatasetDetailPanel(item));

        Ext.Ajax.request({
            url: this.uri,
            method: "GET",
            scope: this,
            success: function(o) {
                var json = Ext.util.JSON.decode(o.responseText);
                if (json) {
                    if (json.features) store_features.loadData(json.features);
                    if (json.annotations) store_annotations.loadData(json.annotations);
                    if (json.statistics) store_statistics.loadData(json.statistics);
                    if (json.alias) store_alias.loadData(json.alias);
                    if (json.references) store_references.loadData(json.references);
                    if (json.associations) store_associations.loadData(json.associations);
                }
            }
        });
    },

    displayDetails: function(a, b, item) {
        if (item && item.parentElement && item.parentElement.id) {
            var sectionType = item.parentElement.id;
            if (sectionType == "features") {
                var record_json = this.dataview_features.getRecord(item).json;
                var uri = record_json.table;
                if (record_json["type"] == "continuous") {
                    this.datasetDetailPanel.showTabs([
                        new org.cancerregulome.redi.DataGridPanel({title: record_json.label, datasetUri: uri, schema: record_json.schema }),
                        new org.cancerregulome.redi.HistogramPanel(uri),
                        new org.cancerregulome.redi.DataGridPanel({title: "Stats By Sample", datasetUri: uri + "_STATS_BY_SAMPLE" }),
                        new org.cancerregulome.redi.DataGridPanel({title: "Stats By Feature", datasetUri: uri + "_STATS_BY_FEATURE" })
                    ]);
                } else {
                    this.datasetDetailPanel.showTabs([
                        new org.cancerregulome.redi.DataGridPanel({title: record_json.label, datasetUri: uri, schema: record_json.schema })
                    ]);
                }
            } else if (sectionType == "annotations") {
                var record_json = this.dataview_annotations.getRecord(item).json;
                var uri = record_json.table;
                this.datasetDetailPanel.showTabs([
                    new org.cancerregulome.redi.DataGridPanel({title: record_json.label, datasetUri: uri, schema: record_json.schema })
                ]);
            } else if (sectionType == "statistics") {
                var record_json = this.dataview_statistics.getRecord(item).json;
                var uri = record_json.table;
                var table = record_json.tableName;
                this.datasetDetailPanel.showTabs([
                    new org.cancerregulome.redi.ScatterplotPanel({
                        title: record_json.label,
                        datasetUri: uri,
                        databaseInfo: {
                            table: table,
                            schema: this.dsid
                        }
                    }),
                    new org.cancerregulome.redi.DataGridPanel({title: record_json.label, datasetUri: uri, schema: record_json.schema })
                ]);
            } else if (sectionType == "alias") {
                var record_json = this.dataview_alias.getRecord(item).json;
                var uri = record_json.table;
                this.datasetDetailPanel.showTabs([
                    new org.cancerregulome.redi.DataGridPanel({title: record_json.label, datasetUri: uri, schema: record_json.schema })
                ]);
            } else if (sectionType == "references") {
                var record_json = this.dataview_references.getRecord(item).json;
                var uri = record_json.table;
                this.datasetDetailPanel.showTabs([
                    new org.cancerregulome.redi.DataGridPanel({title: record_json.label, datasetUri: uri, schema: record_json.schema })
                ]);
            } else if (sectionType == "associations") {
                var record_json = this.dataview_associations.getRecord(item).json;
                var uri = record_json.table;
                this.datasetDetailPanel.showTabs([
                    new org.cancerregulome.redi.DataGridPanel({title: record_json.label, datasetUri: uri, schema: record_json.schema })
                ]);
            } else {
                this.datasetDetailPanel.showTabs();
            }
        }
    }
});

org.cancerregulome.redi.DatasetDetailPanel = Ext.extend(Ext.Panel, {
    layout: "border",
    region: "center",
    padding: "5 5 5 5",
    frame: true,

    constructor: function(json) {
        this.datasetUri = json.uri;

        org.cancerregulome.redi.DatasetDetailPanel.superclass.constructor.call(this);

        this.summaryPanel = this.add({ region: "north", html: json.description });
        this.tabPanel = this.add(new Ext.TabPanel({
            region: "center",
            enableTabScroll: true,
            activeTab: 0,
            items: []
        }));
    },

    showTabs: function(tabs) {
        this.tabPanel.removeAll(true);
        if (tabs) {
            Ext.each(tabs, function(tab) {
                this.tabPanel.add(tab);
            }, this);
            this.tabPanel.activate(0);
        }
    }
});

org.cancerregulome.redi.HistogramPanel = Ext.extend(Object, {
    title: "Histogram",
    html: "TODO: Show Histogram",

    constructor: function(uri) {
        this.datasetUri = uri;
        this.html = "TODO: Show Histogram for " + uri;

        org.cancerregulome.redi.HistogramPanel.superclass.constructor.call(this);
    }
});

org.cancerregulome.redi.ScatterplotPanel = Ext.extend(Ext.Panel, {
    layout: "border",

    constructor: function(config) {
        Ext.apply(this, config);

        org.cancerregulome.redi.ScatterplotPanel.superclass.constructor.call(this);

        var nonNumericFields = new Ext.data.ArrayStore({ fields: ['code', 'label'], data : [] });
        var statsFields = new Ext.data.ArrayStore({ fields: ['code', 'label'], data : [] });

        Ext.Ajax.request({
            url: this.datasetUri,
            method: "GET",
            scope: this,
            success: function(o) {
                var json = Ext.util.JSON.decode(o.responseText);
                if (json && json.items) {
                    var nonNumeric = [];
                    var stats = [];
                    Ext.each(json.items, function(item) {
                        if (item.datatype == "DOUBLE") stats.push([item.name, item.name]);
                        if (item.datatype == "INT") stats.push([item.name, item.name]);
                        if (item.datatype == "BIGINT") stats.push([item.name, item.name]);
                        if (item.datatype == "VARCHAR") nonNumeric.push([item.name, item.name]);
                    });
                    nonNumericFields.loadData(nonNumeric);
                    statsFields.loadData(stats);
                }
            }
        });

        this.resultsPanel = new Ext.Panel({ region: "center", layout: "fit", items: [{ html : "No results found" }] });
        this.add(this.resultsPanel);
        this.add(new Ext.Panel({
            region: "north",
            height: 30,
            layout: "hbox",
            items: [
                new Ext.form.ComboBox({
                    label: "ID",
                    store: nonNumericFields,
                    displayField:'label',
                    mode: 'local',
                    forceSelection: true,
                    triggerAction: 'all',
                    emptyText:'Select identifier to plot',
                    selectOnFocus:true,
                    listeners: {
                        scope: this,
                        select: function(combo,record) { this.selectedDot = record.data.code; }
                    }
                }),
                new Ext.form.ComboBox({
                    label: "X-Axis",
                    store: statsFields,
                    displayField:'label',
                    mode: 'local',
                    forceSelection: true,
                    triggerAction: 'all',
                    emptyText:'Select x-axis statistic',
                    selectOnFocus:true,
                    listeners: {
                        scope: this,
                        select: function(combo,record) { this.selectedX = record.data.code; }
                    }
                }),
                new Ext.form.ComboBox({
                    label: "Y-Axis",
                    store: statsFields,
                    displayField:'label',
                    mode: 'local',
                    forceSelection: true,
                    triggerAction: 'all',
                    emptyText:'Select y-axis statistic',
                    selectOnFocus:true,
                    listeners: {
                        scope: this,
                        select: function(combo,record) { this.selectedY = record.data.code; }
                    }
                }),
                new Ext.Button({ text: "Plot", handler: this.executePlot, scope: this })
            ]
        }));
        this.doLayout();
    },

    executeQuery: function() {
        if (this.selectedDot && this.selectedX && this.selectedY) {
            Ext.Ajax.request({
                url: this.datasetUri + "/query",
                method: "GET",
                scope: this,
                params: {
                    tq: "SELECT " + this.selectedDot + ", " + this.selectedX + ", " + this.selectedY + " LIMIT 100",
                    tqx: "out:json_array"
                },
                success: function(o) {
                    var data = Ext.util.JSON.decode(o.responseText);
                    this.resultsPanel.removeAll(true);
                    this.resultsPanel.add(org.cancerregulome.redi.NewDataGrid(data));
                    this.doLayout();
                }
            });
        }
    },

    executePlot: function() {
        if (this.selectedDot && this.selectedX && this.selectedY) {
            Ext.Ajax.request({
                url: this.datasetUri + "/query",
                method: "GET",
                scope: this,
                params: {
                    tq: "SELECT min(" + this.selectedX + "), max(" + this.selectedX + "), " +
                        "min(" + this.selectedY + "), max(" + this.selectedY + ") " +
                        "LABEL min(" + this.selectedX + ") 'x_min', max(" + this.selectedX + ") 'x_max'," +
                        "min(" + this.selectedY + ") 'y_min', max(" + this.selectedY + ") 'y_max'",
                    tqx: "out:json_array"
                },
                success: function(o) {
                    var data = Ext.util.JSON.decode(o.responseText);
                    this.resultsPanel.removeAll(true);
                    this.resultsPanel.add(new org.cancerregulome.redi.BitmapPlotPanel({
                        data: {
                            statistics: data[0],
                            database: this.databaseInfo,
                            xColumn: this.selectedX,
                            yColumn: this.selectedY,
                            dotLabel: this.selectedDot
                        }
                    }));
                    this.doLayout();
                }
            });
        }
    }
});

org.cancerregulome.redi.DataGridPanel = Ext.extend(Ext.Panel, {
    title: "Data Grid",
    layout: "fit",

    constructor: function(config) {
        Ext.apply(this, config);

        org.cancerregulome.redi.DataGridPanel.superclass.constructor.call(this);

        Ext.Ajax.request({
            url: this.datasetUri + "/query",
            method: "GET",
            params: {
                tq: "LIMIT 100",
                tqx: "out:json_array"
            },
            scope: this,
            success: function(o) {
                var data = Ext.util.JSON.decode(o.responseText);
                this.removeAll(true);
                this.add(org.cancerregulome.redi.NewDataGrid(data, this.schema));
                this.doLayout();
            },
            failure: function(o) {
                this.add({ html: "<b>" + o.statusText + "</b><br/>" + o.responseText });
            }
        });
    }
});

org.cancerregulome.redi.BitmapPlotPanel = Ext.extend(Ext.Panel, {
    title: "Plot",
    layout: "fit",

    constructor: function(config) {
        Ext.apply(this, config);

        org.cancerregulome.redi.BitmapPlotPanel.superclass.constructor.call(this);
    },

    initComponent: function() {
        Ext.apply(this, {
            listeners: {
                afterrender: {
                    scope: this,
                    fn: function() {
                        this.initPlot();
                    }
                }
            }
        });

        org.cancerregulome.redi.BitmapPlotPanel.superclass.initComponent.call(this);
    },

    initPlot: function() {
        var scatter_plot = new vq.BitmapScatterPlot();

        var plot_data = {
            DATATYPE : "vq.models.BitmapScatterPlotData",
            CONTENTS : {
                PLOT : {
                    container: this.getEl().dom,
                    width : 1000, height: 1000,
                    bitmap_width: 900, bitmap_height: 900,
                    bitmap_horizontal_padding: 50,
                    bitmap_vertical_padding: 50,
                    vertical_padding : 60,
                    horizontal_padding: 60,
                    empty_container_div: true,
                    font :"14px sans"},
                regression: 'none',
                xcolumnid: this.data.xColumn,
                ycolumnid: this.data.yColumn,
                valuecolumnid: 'id'
            }
        };

        scatter_plot.draw(plot_data);

        var bitmap_uri = "/addama/proxies/big_scatter/?";
        var params = Ext.urlEncode({
            width: 900,
            height: 900,
            hpad: 50,
            vpad: 50,
            dataset: this.data.database.schema,
            table: this.data.database.table,
            x: this.data.xColumn,
            y: this.data.yColumn,
            label: this.data.dotLabel
        });

        scatter_plot.resetData({
            data_xmin: this.data.statistics.x_min,
            data_xmax: this.data.statistics.x_max,
            data_ymin: this.data.statistics.y_min,
            data_ymax: this.data.statistics.y_max,
            plot_uri: bitmap_uri + params
        });

        scatter_plot.enableBrush();
    }
});

org.cancerregulome.redi.NewDataGrid = function(data, schema) {
    var fields = [];
    var columns = [];
    if (schema && schema.length) {
        Ext.each(schema, function(schemaItem) {
            var key = schemaItem.name;
            fields.push(key);

            if (!schemaItem.id) schemaItem.id = key;
            if (!schemaItem.header) schemaItem.header = schemaItem.label;
            schemaItem.dataIndex = key;
            schemaItem.sortable = true;
            schemaItem.width = 100;

            columns.push(schemaItem);
        });
    } else if (data && data.length) {
        Ext.each(Object.keys(data[0]), function(key) {
            fields.push(key);
            columns.push({ id: key, header: key, dataIndex: key, sortable: true, width: 100 });
        });
    } else {
        return { html : "No data found" };
    }

    var store = new Ext.data.JsonStore({ storeId : 'gridResults', autoDestroy: true, root : 'results', fields: fields });
    store.loadData({ results: data });

    return new Ext.grid.GridPanel({
        store: store,
        colModel: new Ext.grid.ColumnModel({
            defaults: { width: 200, sortable: true },
            columns: columns
        }),
        stripeRows: true,
        iconCls: 'icon-grid'
    });
};

org.cancerregulome.redi.LabelSorter = function(a, b) {
    if (a && b && a.label && b.label) {
        var labelA = a.label.toLowerCase();
        var labelB = b.label.toLowerCase()
        if (labelA < labelB) return -1;
        if (labelA > labelB) return 1;
    }
    return 0;
};